package com.party.refund.biz;

import com.party.common.constant.Constant;
import com.party.common.utils.refund.WechatPayUtils;
import com.party.core.exception.BusinessException;
import com.party.core.model.crowdfund.Project;
import com.party.core.model.crowdfund.Support;
import com.party.core.model.order.OrderForm;
import com.party.core.model.order.OrderFormInfo;
import com.party.core.service.activity.IActivityService;
import com.party.core.service.crowdfund.*;
import com.party.core.service.crowdfund.biz.ProjectDetailCountBizService;
import com.party.core.service.distributor.IDistributorRelationService;
import com.party.core.service.member.IMemberService;
import com.party.core.service.order.IOrderFormInfoService;
import com.party.core.service.order.IOrderFormService;
import com.party.core.service.order.IOrderRefundService;
import com.party.core.service.order.IOrderRefundTradeService;
import com.party.core.service.wechat.IWechatMerchantsService;
import com.party.pay.model.refund.WechatPayRefundResponse;
import com.party.refund.jms.service.ISupportRefundPubulisherService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @Author: huangzequn
 * @Date: 2019/5/16 16:05
 */
@SuppressWarnings("all")
@Service
public class SupportBizService {

    @Autowired
    private ISupportService supportService;

    @Autowired
    private IOrderRefundTradeService orderRefundTradeService;

    @Autowired
    private IOrderFormService orderFormService;

    @Autowired
    private IProjectService projectService;

    @Autowired
    private ITargetProjectService targetProjectService;

    @Autowired
    private IActivityService activityService;

    @Autowired
    private ISupportRefundService supportRefundService;

    @Autowired
    private IProjectRefundService projectRefundService;

    @Autowired
    private IOrderRefundService orderRefundService;

    @Autowired
    private IProjectReviseService projectReviseService;

    @Autowired
    private ProjectDetailCountBizService projectDetailCountBizService;

    @Autowired
    private IWechatMerchantsService wechatMerchantsService;

    @Autowired
    private IDistributorRelationService distributorRelationService;

    @Autowired
    private ICrowdfundEventService crowdfundEventService;

    @Autowired
    private RefundBizService refundBizService;

    @Autowired
    private IOrderFormInfoService orderFormInfoService;

    @Autowired
    private ISupportRefundPubulisherService supportRefundPubulisherService;

    @Autowired
    private RedisTemplate redisTemplate;

    private static final String SYSTEMERROR = "SYSTEMERROR";//微信接口 系统超时等
    private static final String BIZERR_NEED_RETRY = "BIZERR_NEED_RETRY";//微信并发情况下，业务被拒绝，商户重试即可解决
    private static final String INVALID_REQ_TOO_MUCH = "INVALID_REQ_TOO_MUCH";//连续错误请求数过多被系统短暂屏蔽
    private static final String FREQUENCY_LIMITED = "FREQUENCY_LIMITED";//频率限制
    //private ExecutorService retryThreadPool = Executors.newFixedThreadPool(30);
    private static Logger logger = LoggerFactory.getLogger(SupportBizService.class);

    public static List<String> list = new ArrayList<>();

    /**
     * 支持退款信息
     *
     * @param id 支持编号
     */
    public void refund(String id) {
        Support support = supportService.get(id);
        OrderFormInfo orderFormInfo = orderFormInfoService.findByOrderId(support.getOrderId());
        Project project = projectService.get(support.getProjectId());
        if(null != orderFormInfo && list.size() > 0){
            for (String mchId : list) {
                if(orderFormInfo.getMchId().equals(mchId)){
                    logger.info("{}：商户号余额不足,支持者id为：{}",mchId,id);
                    //商户号余额不足，不调微信退款了；
                    String responseData = "<xml>"+
                            "<return_code><![CDATA[SUCCESS]]></return_code>"+
                            "<return_msg><![CDATA[OK]]></return_msg>"+
                            "<result_code><![CDATA[FAIL]]></result_code>"+
                            "<err_code><![CDATA[NOTENOUGH]]></err_code>"+
                            "<err_code_des><![CDATA[余额不足,未退款]]></err_code_des>"+
                            "</xml>";
                    WechatPayRefundResponse response = WechatPayUtils.xmlToBean(responseData, WechatPayRefundResponse.class);
                    orderRefundService.orderTrade(support.getOrderId(), response);
                    support.setPayStatus(Constant.SUPPORT_PAY_STATUS_FAIL);
                    supportService.update(support);
                    projectReviseService.reviseFavorer(project.getId());
                    return;
                }
            }
        }
        //验证是否已经退款
        OrderForm orderForm = orderFormService.get(support.getOrderId());
        if (null != orderForm && orderForm.getStatus().equals(Constant.SUPPORT_PAY_STATUS_REFUND)) {
            return;
        }
        WechatPayRefundResponse response = null;
        try {
            long start = System.currentTimeMillis();
            response = (WechatPayRefundResponse) refundBizService.refund(support.getOrderId());
            long end = System.currentTimeMillis();
            logger.info("{}:线程调微信退款，执行时间：{}(ms)", Thread.currentThread().getName(), (end - start));
        } catch (BusinessException be) {
            WechatPayRefundResponse rp = new WechatPayRefundResponse();
            rp.setErrCodeDes(be.getMessage());
            orderRefundService.orderTrade(support.getOrderId(), rp);
        } catch (Exception e) {
            //退款失败
            projectService.crowdfundRefundFaile(project);//将zc_project状态置为退款失败的状态
            support.setPayStatus(Constant.SUPPORT_PAY_STATUS_FAIL);
            supportService.update(support);
            logger.info("众筹支持订单退款异常", e);
        }
        if (null == response) {
            //退款失败
            projectService.crowdfundRefundFaile(project);//将zc_project状态置为退款失败的状态
            support.setPayStatus(Constant.SUPPORT_PAY_STATUS_FAIL);
            supportService.update(support);
            return;
        }

        //退款成功
        if (Constant.WECHAT_SUCCESS.equals(response.getReturnCode()) && Constant.WECHAT_SUCCESS.equals(response.getResultCode())) {
            Object object = redisTemplate.opsForValue().get(id);
            if(null != object){
                logger.info("线程:{},支持者id为:{},重试执行了{}次,退款成功了", Thread.currentThread().getName(),id, object);
            }
            long start = System.currentTimeMillis();
            supportRefundService.refund(support, response);
            long end = System.currentTimeMillis();
            logger.info("{}:退款成功,开始时间:{},结束时间:{},执行时间:{}(ms)",
                    Thread.currentThread().getName(), start, end, (end - start));
            //众筹是否全部退完
            boolean refundAll = supportService.isRefundAll(project.getId());
            if (refundAll) {
                projectRefundService.refund(project);
            }
        }

        //退款失败
        else {
            //如果订单已经退款
            if (Constant.REFUND_ALL_DES.equals(response.getErrCodeDes())) {
                supportRefundService.refund(support, response);
                //众筹是否全部退完
                boolean refundAll = supportService.isRefundAll(project.getId());
                if (refundAll) {
                    projectRefundService.refund(project);
                }
            } else {
                //退款重试机制
                boolean find = this.refundRetry(response, id);
                if(find){
                    return;
                }
                logger.info("线程:{},支持者id为:{},重试执行了{}次还是退款失败,微信返回的退款失败信息:{}",
                        Thread.currentThread().getName(), id, redisTemplate.opsForValue().get(id),response.getErrCode());
                //退款失败
                projectService.crowdfundRefundFaile(project);//将zc_project状态置为退款失败的状态
                support.setPayStatus(Constant.SUPPORT_PAY_STATUS_FAIL);
                supportService.update(support);
                orderRefundService.orderTrade(support.getOrderId(), response);
                if("NOTENOUGH".equals(response.getErrCode()) && !list.contains(response.getMchId())){
                    list.add(response.getMchId());
                }
            }
        }

        // 退款后, 众筹的统计分析修改
        try {
            projectDetailCountBizService.countProjectSomeDay(support.getProjectId(), support.getCreateDate());
        } catch (Exception e) {
            logger.error("退款后, 众筹的统计分析修改异常", e);
        }
        boolean refundAll = supportService.isPayStatusChangeAll(project.getId());
        if (refundAll) {
            Integer refundFailCount = supportService.refundAllFailCount(project.getId());
            logger.info("有" + refundFailCount + "个人退款失败");
            projectReviseService.reviseFavorer(project.getId());
        }
    }


    /**
    * @Author hzq
    * @Description //退款重试机制
    * @Date 16:19 2019/5/23
    * @param response
    * @param id  支持者id
    * @return
    **/
    public boolean refundRetry(WechatPayRefundResponse response,String id){
        //重试机制  两次 设置60分钟有效时间
        if (SYSTEMERROR.equals(response.getErrCode()) || BIZERR_NEED_RETRY.equals(response.getErrCode())
                || INVALID_REQ_TOO_MUCH.equals(response.getErrCode()) || FREQUENCY_LIMITED.equals(response.getErrCode())) {
            logger.info("微信返回的退款失败信息:{},支持者id为：{}",response.getErrCode(),id);
            try {
                Object object = redisTemplate.opsForValue().get(id);
                if (null != object) {
                    Integer number = Integer.valueOf(object.toString());
                    if (number < 2) {
                        redisTemplate.opsForValue().set(id, number + 1);
                        redisTemplate.expire(id, 60, TimeUnit.MINUTES);
                        Thread.sleep(1000);
                        this.refund(id);
                        return true;
                    }else if(number == 2){
                        logger.info("如果重试了2次还是失败  从新入队列+++");
                        //如果重试了2次还是失败  从新入队列
                        redisTemplate.opsForValue().set(id, number + 1);
                        redisTemplate.expire(id, 60, TimeUnit.MINUTES);
                        supportRefundPubulisherService.send(id,"YES");
                        return true;
                    }
                } else {
                    redisTemplate.opsForValue().set(id, Integer.valueOf(1));
                    redisTemplate.expire(id, 60, TimeUnit.MINUTES);
                    Thread.sleep(1000);
                    this.refund(id);
                    return true;
                }
            } catch (Exception e) {
                logger.info("退款重试异常支持者id为：" + id, e);
            }
        }
        return false;
    }
}
